package com.ld.common.util.filelistener.commonio;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;

import com.ld.common.util.filelistener.commonio.impl.AbstractChangedHandler;
import com.ld.shieldsb.common.core.model.Result;
import com.ld.shieldsb.common.core.util.PathUtil;
import com.ld.shieldsb.common.core.util.StringUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * 文件变化监听器（common-io版）使用FileAlterationMonitor类监听文件变化 <br>
 * 注： <br>
 * 1、FileAlterationMonitor默认响应时间为10s，即添加文件后可能要过10s才接到通知。所以一般使用带时间参数的构造器（单位毫秒）。<br>
 * 2、也可以通过继承FileAlterationListenerAdaptor来实现监听，目前该类为空实现。两种方式各有优劣。<br>
 * 3、父目录的下的文件变动时，会触发2个事件：a，子文件FileChange;b，父目录的DirectoryChange事件；<br>
 * 4、重命名文件（夹），会同时触发：FileCreate和FileDelete <br>
 * 5、如果拷贝某个工程时，工程内的每个文件都会触发事件，所以队列添加事件的算法需要好好设计。<br>
 * 6、windows系统，文件拷贝过程不触发事件，拷完后触发FileChange，Linux，拷贝过程一直触发FileChange<br>
 * 
 * 总结：由于在window2003等系统，在拷贝文件结束后也不触发FileChange，所以要真正跨平台，还得结合Jnotify和FileAlteration
 * 
 * @ClassName FileChangedListener
 * @author <a href="mailto:donggongai@126.com" target="_blank">吕凯</a>
 * @date 2019年1月17日 下午5:04:56
 *
 */
@Slf4j
public class FileChangedListenerManager {
    private static final Map<String, FileChangedListenerModel> LISTENER_MAP = new LinkedHashMap<>(); // 管理器

    public static void main(String[] args) {
        try {
            FileChangedListenerModel listener = new FileChangedListenerModel();
            listener.setName("test");
            listener.setKeyCode("test");
            listener.setPath(PathUtil.getClassRootPath() + "com/ld");
            listener.setListener(new AbstractChangedHandler());
            FileChangedListenerManager.register(listener);
            FileChangedListenerManager.start(listener.getKeyCode());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Result register(FileChangedListenerModel listener) {
        Result result = new Result();
        result.setSuccess(false);
        String keyCode = listener.getKeyCode();
        if (StringUtils.isBlank(listener.getName())) {
            result.setMessage("name不能为空！");
            return result;
        }
        if (StringUtils.isBlank(keyCode)) {
            result.setMessage("识别码(KeyCode)不能为空！");
            return result;
        }
        FileChangedListenerModel cacheModel = LISTENER_MAP.get(keyCode);
        if (cacheModel != null) {
            result.setMessage("识别码(KeyCode)为" + keyCode + "的监听器已经存在！监听器名称为：" + cacheModel.getName());
            return result;
        }
        // 文件监控线程
        log.warn("注册监听器：" + listener.getName() + " " + listener.getPath());
        // 添加监听
        LISTENER_MAP.put(keyCode, listener);
        result.setSuccess(true);
        result.setData(listener);
        return result;
    }

    public static Result start(String keyCode) throws Exception {
        Result result = new Result();
        result.setSuccess(false);
        if (!LISTENER_MAP.containsKey(keyCode)) {
            result.setMessage("识别码(KeyCode)为" + keyCode + "的监听器尚未注册，请先注册！");
            return result;
        }
        FileChangedListenerModel listener = LISTENER_MAP.get(keyCode);
        // 文件监控线程
        log.warn("启动文件监听 监听目录：" + listener.getPath());
        listener.start();
        result.setSuccess(true);
        return result;
    }

    /**
     * 停止监听器
     * 
     * @Title stop
     * @author 吕凯
     * @date 2019年1月18日 上午9:03:57
     * @param keyCode
     * @return Result
     * @throws Exception
     */
    public static Result stop(String keyCode) throws Exception {
        Result result = new Result();
        result.setSuccess(false);
        if (!LISTENER_MAP.containsKey(keyCode)) {
            result.setMessage("识别码(KeyCode)为" + keyCode + "的监听器尚未注册，请先注册！");
            return result;
        }
        FileChangedListenerModel listener = LISTENER_MAP.get(keyCode);
        Boolean isStarted = listener.isStarted();
        if (!isStarted) {
            result.setMessage("识别码(KeyCode)为" + keyCode + "的监听器尚未启动！");
            return result;
        }
        listener.stop();
        LISTENER_MAP.remove(keyCode);
        result.setSuccess(true);
        return result;
    }

    /**
     * 关闭监听
     * 
     * @throws IOException
     */
    public static void shutdown() {
        java.util.Set<String> keySet = LISTENER_MAP.keySet();
        if (CollectionUtils.isNotEmpty(keySet)) {
            keySet.forEach(keyCode -> {
                try {
                    FileChangedListenerModel listener = LISTENER_MAP.get(keyCode);
                    Boolean isStarted = listener.isStarted();
                    if (isStarted) {
                        listener.stop();
                    }
                } catch (Exception e) {
                    log.error("", e);
                }
            });
            LISTENER_MAP.clear();
        }
    }

    /**
     * 获取监听器
     * 
     * @Title get
     * @author 吕凯
     * @date 2019年1月18日 下午3:28:39
     * @param keyCode
     * @return FileChangedListenerModel
     */
    public static FileChangedListenerModel get(String keyCode) {
        FileChangedListenerModel listenerModel = LISTENER_MAP.get(keyCode);
        return listenerModel;
    }

    /**
     * 获取监听器的Map，key为keyCode
     * 
     * @Title getAllCacheModels
     * @author 吕凯
     * @date 2019年1月18日 下午3:28:56
     * @return Map<String,FileChangedListenerModel>
     */
    public static Map<String, FileChangedListenerModel> getAllCacheModels() {
        return LISTENER_MAP;
    }

}
